package com.ruoyi.event.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.event.config.WxMiniAppConfig;
import com.ruoyi.event.domain.WxLoginDTO;
import com.ruoyi.event.service.impl.EventInfoListServiceImpl;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.compare.ObjectToStringComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class WxLoginService {
    private static final Logger log = LoggerFactory.getLogger(WxLoginService.class);


    @Autowired
    private WxMiniAppConfig wxConfig;
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 微信登录核心方法：获取openid和手机号
     */
    public Map<String, Object> login(String type, WxLoginDTO loginDTO) {
        Map<String, Object> result = new HashMap<>();
        String sessionKey = "";
        log.info(type);
        log.info(loginDTO.toString());
        if (StringUtils.isNotBlank(type) && type.equals("login")) {
            // 1. 通过code获取openid和session_key
            Map<String, String> sessionMap = getSessionKey(loginDTO.getCode());
            String openid = sessionMap.get("openid");
            sessionKey = sessionMap.get("session_key");
            log.info(openid);
            result.put("openid", openid);
            result.put("sessionKey", sessionKey);
        }
        log.info(sessionKey);
        // 2. 如果传递了手机号加密数据，则解密手机号
        if (StringUtils.isNotBlank(loginDTO.getEncryptedData()) && StringUtils.isNotBlank(loginDTO.getIv())) {
            String phone = decodePhoneNumber(loginDTO.getEncryptedData(), loginDTO.getSessionKey(), loginDTO.getIv());
            log.info(phone);
            result.put("phone", phone);
        }

        return result;
    }

    /**
     * 调用微信接口获取session_key和openid
     */
    private Map<String, String> getSessionKey(String code) {
        // 拼接请求参数
        String url = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                wxConfig.getJscode2session(),
                wxConfig.getAppid(),
                wxConfig.getSecret(),
                code);
        log.info(url);
        // 调用微信接口
        String response = restTemplate.getForObject(url, String.class);
        Map<String, String> result = JSON.parseObject(response, Map.class);

        // 处理微信返回的错误
        if (result.containsKey("errcode") && !"0".equals(result.get("errcode"))) {
            throw new RuntimeException("微信登录失败：" + result.get("errmsg"));
        }
        return result;
    }

    /**
     * 解密手机号
     * 参考微信文档：https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
     */
    private String decodePhoneNumber(String encryptedData, String sessionKey, String iv) {
        log.info(encryptedData);
        log.info(sessionKey);
        log.info(iv);
        try {
            // 1. 解密sessionKey和iv
            byte[] sessionKeyBytes = Base64.decodeBase64(sessionKey);
            byte[] encryptedDataBytes = Base64.decodeBase64(encryptedData);
            byte[] ivBytes = Base64.decodeBase64(iv);

            // 2. 初始化加密算法
            SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
            //Cipher cipher = Cipher.getInstance(wxConfig.getPhoneDecodeMode() + "/NoPadding");
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

            log.info(keySpec.getAlgorithm());
            // 3. 解密并解析手机号
            byte[] decrypted = cipher.doFinal(encryptedDataBytes);
            String decryptedStr = new String(decrypted, StandardCharsets.UTF_8);
            Map<String, Object> phoneMap = JSON.parseObject(decryptedStr, Map.class);
            log.info(phoneMap.toString());
            return phoneMap.get("phoneNumber").toString();
        } catch (Exception e) {
            throw new RuntimeException("手机号解密失败：" + e.getMessage());
        }
    }

    /**
     * 微信登录核心方法：获取openid和手机号
     */
    public Map<String, Object> getphone(WxLoginDTO loginDTO) {
    Map<String, Object> result = new HashMap<>();

    log.info(loginDTO.getCode());
    // 1. 校验前端参数（phoneCode必传）
    String phoneCode = loginDTO.getCode();
        if(phoneCode ==null||phoneCode.trim().isEmpty()) {
        result.put("success", false);
        result.put("msg", "手机号code不能为空");
        return result;
    }

    log.info(phoneCode);

    try {
        // 2. 第一步：获取小程序access_token（微信接口调用凭证）
        String accessToken = getAccessToken();
        if (accessToken == null) {
            result.put("success", false);
            result.put("msg", "获取access_token失败");
            return result;
        }
        log.info(accessToken);
        // 3. 第二步：调用微信新版接口，用phoneCode换手机号
        String wxApiUrl = String.format(
                "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s",
                accessToken
        );
        log.info(wxApiUrl);


        // 构造请求参数（仅需传递phoneCode）
        Map<String, String> requestData = new HashMap<>();
        requestData.put("code", phoneCode);
        log.info(requestData.toString());

        // 构造请求头（明确指定JSON格式）
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        String jsonStr = JSON.toJSONString(requestData);
        log.info(jsonStr);
        // 构造HttpEntity（包含头和请求体）
        HttpEntity<String> requestEntity = new HttpEntity<>(jsonStr, headers);


        // 发送POST请求（微信该接口要求POST，参数为JSON格式）
        JSONObject wxResponse = restTemplate.postForObject(
                wxApiUrl,
                jsonStr, // 传递包含头和请求体的HttpEntity
                JSONObject.class
        );

        // 4. 解析微信返回结果
        if (wxResponse == null) {
            log.info("微信接口无响应");
            throw new RuntimeException("微信接口无响应");
        }else {
            log.info("微信接口有响应");
        }

        int errCode = wxResponse.getIntValue("errcode");
        if (errCode != 0) {
            // 错误处理（如code过期、无效）
            log.info("获取手机号失败：" + "（code：" + errCode);
            String errMsg = wxResponse.getString("errmsg");
            throw new RuntimeException("获取手机号失败：" + errMsg + "（code：" + errCode + "）");
        }

        // 5. 提取手机号（微信返回在phone_info中）
        JSONObject phoneInfo = wxResponse.getJSONObject("phone_info");
        String phoneNumber = phoneInfo.getString("phoneNumber"); // 最终手机号
        log.info(phoneNumber);
        // 6. 返回结果给前端
        result.put("success", true);
        result.put("msg", "获取手机号成功");
        result.put("data", Map.of("phoneNumber", phoneNumber));

    } catch(
    Exception e){
        log.info(e.getMessage());
        result.put("success", false);
        result.put("msg", e.getMessage());
    }

        return result;
    }

    /**
     * 辅助方法：获取小程序access_token（通过appid和appsecret）
     */
    private String getAccessToken() {
        try {
            // 微信获取access_token的接口
            String accessTokenUrl = String.format(
                    "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                    wxConfig.getAppid(),
                    wxConfig.getSecret()
            );

            // 发送GET请求
            JSONObject response = restTemplate.getForObject(accessTokenUrl, JSONObject.class);
            if (response == null || response.getIntValue("errcode") != 0) {
                String errMsg = response != null ? response.getString("errmsg") : "获取access_token接口无响应";
                System.err.println("获取access_token失败：" + errMsg);
                return null;
            }

            // access_token有效期2小时，建议缓存（此处简化，未做缓存）
            return response.getString("access_token");

        } catch (Exception e) {
            System.err.println("获取access_token异常：" + e.getMessage());
            return null;
        }
    }


}